package com.bnq.logc.printer

import android.util.Log
import com.bnq.logc.LogcLevel
import com.bnq.logc.LogcManager
import com.bnq.logc.action.WriteAction
import com.bnq.logc.utils.DateUtil
import com.cj.clog.Clog
import java.io.File
import java.io.FileWriter

class MmapLogcPrinter(val path:String) : LogcPrinter,PrinterCloseable {

    private val logPath= File(path)
    private val logFile = File(logPath,"${DateUtil.formatDateTime(System.currentTimeMillis(),pattern = "yyyy-MM-dd")}.log")

    private fun getFile(): File {
        if(!logPath.exists()){
            logPath.mkdirs()
        }
        if(!logFile.exists()){
            val success = logFile.createNewFile()
            if(!success && LogcManager.getConfig().mIsDebug){
                Log.e("Logc","创建本地储存log文件失败：${logFile.absolutePath}")
            }
        }
        return logFile
    }

    val config = LogcManager.getConfig()

    val clog:Clog? = createClog()

    val mmapSafe = config.mLogWriteModeConfig.mmapSafe

    private fun createClog():Clog?{
        val encryptMode = config.mLogWriteModeConfig.encryptMode?.getClogEncryptMode()
        val serverPublicKey = config.mLogWriteModeConfig.serverPublicKey
        val serverPrivateKey = config.mLogWriteModeConfig.serverPrivateKey
        val mmapSafe = config.mLogWriteModeConfig.mmapSafe
        if(encryptMode != null && serverPublicKey != null && serverPrivateKey != null){
            return try {
                val clog = Clog.create(
                    getFile().absolutePath, Clog.WriteMode.Auto, Clog.CompressMode.None,
                    encryptMode, serverPublicKey, serverPrivateKey
                )
                if (mmapSafe && clog == null) {
                    val action = WriteAction(
                        LogcLevel.ERROR,
                        "MMAP-SAFE",
                        "底层C++创建Clog失败：${logFile.absolutePath}",
                        System.currentTimeMillis(),
                        "${Thread.currentThread().name}:${Thread.currentThread().id}",
                        false
                    )
                    safePrinter(action.getLogMessage())
                    Log.e("Logc", "创建Clog失败：${logFile.absolutePath}")
                }
                clog
            }catch (e:Exception){
                e.printStackTrace()
                null
            }
        }else{
            if(LogcManager.getConfig().mIsDebug){
                Log.e("Logc","创建Clog失败，缺少配置参数：encryptMode=$encryptMode,serverPublicKey=$serverPublicKey,serverPrivateKey=$serverPrivateKey")
            }
            if(mmapSafe){
                val action = WriteAction(
                    LogcLevel.ERROR,
                    "MMAP-SAFE",
                    "创建Clog失败，缺少配置参数：encryptMode=$encryptMode,serverPublicKey=$serverPublicKey,serverPrivateKey=$serverPrivateKey",
                    System.currentTimeMillis(),
                    "${Thread.currentThread().name}:${Thread.currentThread().id}",
                    false
                )
                safePrinter(action.getLogMessage())
            }
            return null
        }
    }

    override fun isEnabled(): Boolean = config.mLogWriteModeConfig.isMMAP()

    override fun print(message: String) {
        try{
            val ret = clog?.write(message)?:false
            if(!ret && mmapSafe){
                safePrinter(message,LogcLevel.RECORD)
            }
        }catch (e:Exception){
            e.printStackTrace()
            if(LogcManager.getConfig().mIsDebug){
                Log.e("Logc","写本地log失败：${logFile.absolutePath}, exception:${e.message}")
                throw e
            }
            if(mmapSafe){
                val action = WriteAction(
                    LogcLevel.ERROR,
                    "MMAP-SAFE",
                    "MMAP写本地log失败：${logFile.absolutePath}, exception:${e.message}",
                    System.currentTimeMillis(),
                    "${Thread.currentThread().name}:${Thread.currentThread().id}",
                    false
                )
                safePrinter(action.getLogMessage())
                safePrinter(message)
            }
        }
    }

    override fun close() {
        clog?.close()
    }




    private var _safePrinter:LogcPrinter? = null
    @Synchronized
    private fun getSafePrinter():LogcPrinter{
        if(_safePrinter == null){
            _safePrinter = _SafeMmmapLogcPrinter(path)
        }
        return _safePrinter!!
    }

    private fun safePrinter(message: String,level:Int = LogcLevel.ERROR){
        getSafePrinter().print(message)
        LogcManager.sendOnly(level,"MMAP-SAFE",message)
    }
}

private class _SafeMmmapLogcPrinter(path: String) :LogcPrinter{
    private val suffix = ".mmap-safe"
    private val logPath= File(path)//File(context.getExternalFilesDir(null),"log")
    private val logFile = File(logPath,"${DateUtil.formatDateTime(System.currentTimeMillis(),pattern = "yyyy-MM-dd")}${suffix}.log")

    private fun getFile(): File {
        if(!logPath.exists()){
            logPath.mkdirs()
        }
        if(!logFile.exists()){
            val success = logFile.createNewFile()
            if(!success && LogcManager.getConfig().mIsDebug){
                Log.e("Logc","创建本地储存log文件失败：${logFile.absolutePath}")
            }
        }
        return logFile
    }

    override fun isEnabled(): Boolean = true

    override fun print(message: String) {
        try{
            FileWriter(getFile(),true).use { out ->
                out.write(message)
                out.flush()
            }
        }catch (e:Exception){
            e.printStackTrace()
            if(LogcManager.getConfig().mIsDebug){
                Log.e("Logc","写本地log失败：${logFile.absolutePath}")
                throw e
            }
        }
    }

}